/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_NODE_IMAGE_H
#define IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_NODE_IMAGE_H

#include "imageknife_trace.h"
#include "task_worker.h"
#include "imageknife_node_internal.h"
namespace ImageKnifePro {

class ImageKnifeNodeImage : public ImageKnifeNodeInternal, public std::enable_shared_from_this<ImageKnifeNodeImage> {
public:
    explicit ImageKnifeNodeImage(std::shared_ptr<ImageKnifeOption> option);

    // 其他组件实现Image Node
    ImageKnifeNodeImage(std::shared_ptr<ImageKnifeOption> option, ArkUI_NodeHandle handle)
        : ImageKnifeNodeInternal(option, handle, true)
    {
    }

    ~ImageKnifeNodeImage() override
    {
        if (onImageComplete_ != nullptr && useOnComplete_ == true) {
            GetNodeAPI()->unregisterNodeEvent(handle, NODE_IMAGE_ON_COMPLETE);
        }
        mainData_ = nullptr;
    }

    bool Display(std::shared_ptr<ImageDataCacheInternal> data, bool isMainSrc) override;

    // Dispose或Clear时终止动图播放
    void TerminateAnimation() override;
    void Draggable(bool draggable) override
    {
        ArkUI_NumberValue numb = {.i32 = 0};
        if (draggable) {
            numb.i32 = 1;
        }
        ArkUI_AttributeItem item = {.value = &numb, .size = 1};
        GetNodeAPI()->setAttribute(handle, NODE_IMAGE_DRAGGABLE, &item);
    }

    void FitImage(int fitEnum) override
    {
        ArkUI_NumberValue imageFitEnum = {.i32 = fitEnum};
        ArkUI_AttributeItem item = {.value = &imageFitEnum, .size = 1};
        GetNodeAPI()->setAttribute(handle, NODE_IMAGE_OBJECT_FIT, &item);
    }

    void SetColorFilter(OH_Drawing_ColorFilter *colorFilter) override
    {
        IMAGE_KNIFE_CHECK(colorFilter == nullptr, "OH_Drawing_ColorFilter Is NULL");
        ArkUI_AttributeItem item = {.object = colorFilter};
        GetNodeAPI()->setAttribute(handle, NODE_IMAGE_COLOR_FILTER, &item);
        colorFilter_ = true;
    }

    void RemoveColorFilter() override
    {
        if (colorFilter_) {
            GetNodeAPI()->resetAttribute(handle, NODE_IMAGE_COLOR_FILTER);
            colorFilter_ = false;
        }
    }

    void RefreshImage() override
    {
        // 动图本身是在变化的不需刷新，且刷新会导致从头播放，仅在播放停止的时候刷新：更新尾帧的显示效果
        if (!playAnimation_ || animationState_ == ARKUI_ANIMATION_STATUS_STOPPED) {
            GetNodeAPI()->resetAttribute(handle, NODE_IMAGE_SRC);
            Display(mainData_, false);
        }
    }

    void UpdateAnimatorOption(std::shared_ptr<AnimatorOption> option) override;
protected:
    bool triggerOnCompleteCallback_ = false;
private:
    bool useOnComplete_ = false;
    std::function<void(EventImage image)> onImageComplete_ = nullptr;

    std::shared_ptr<ImageDataCacheInternal> mainData_ = nullptr;

    // ------ 动图播放相关 -----
    // 动图播放数据
    std::shared_ptr<ImageDataCacheInternal> animationData_ = nullptr;
    // 逐帧解码task,能获取解码后的当前帧
    std::shared_ptr<ImageKnifeTaskInternal> decodeTask_ = nullptr;
    // 逐帧解码imageSource对象，用于default decode interceptor
    std::shared_ptr<DecodeImageSource> decodeImageSource_ = nullptr;
    // 动图状态
    ArkUI_AnimationStatus animationState_ = ARKUI_ANIMATION_STATUS_RUNNING;
    // 用户对动图的设置项
    std::shared_ptr<AnimatorOption> animatorOption_ = nullptr;
    // 播放次数
    int iterations_ = -1;
    // 当前展示的是否为动图
    bool playAnimation_ = false;
    // 是否逆序播放
    bool reverse_ = false;
    // 首帧
    int initialFrame_ = 0;
    // 尾帧
    int lastFrame_ = 0;
    // 当前播放的帧
    int currentFrame_ = 0;
    // 当前播放的次数
    int currentIteration_ = 0;
    // 图片版本，用于判断是否为最新
    int imageVersionId_ = 0;
    // 动图任务handle 用于取消延时播放任务
    std::shared_ptr<TaskWorker::TaskHandle> animationTaskHandle_ = nullptr;

    bool colorFilter_ = false;

    /**
     * @brief 播放动图的入口，根据状态设置首尾帧
     * @param data 需要播放的动图
     * @return 返回ture则播放成功，否则data检查失败
     */
    bool DisplayAnimation(std::shared_ptr<ImageDataCacheInternal> data);

    /**
     * @brief 播放动图帧，依据状态，传入最新的pictureId时至少会展示一帧
     * 当前帧播放后，依据状态结束播放，或者延时播放下一帧
     * animationState_ 为Running时，持续循环播放指定次数 * 动图帧时
     * animationState_ 为Pause时， 播放完当前帧后停止
     * animationState_ 为Initial时，播放首帧，并停止
     * animationState_ 为Stop时，播放尾帧，并停止
     * @param versionId 图片的版本号，过期的图片不进行设置播放
     */
    void DisplayNextFrame(int versionId);

    void DisplayCurrentFrame();
    void CancelPreviousAnimation();
    void PrepareNextFrame(int versionId);
    void DecodeFrame(bool immediately);

    void SetResizeableOption(std::shared_ptr<ResizableOption> resizeable) override;
    void RemoveResizeableOption() override;

    virtual bool DrawingFrame(std::shared_ptr<ImageDataCacheInternal> data, int frameCount = 0);

    void AnimationIterate();

    void AnimationSwitchToRunning();
    void AnimationSwitchToStop();
    void AnimationSwitchToInitial();
    void AnimationSwitchToPause();

    void OnDerivedNodeEvent(ArkUI_NodeEvent *event) override
    {
        auto eventType = OH_ArkUI_NodeEvent_GetEventType(event);
        switch (eventType) {
            case NODE_IMAGE_ON_COMPLETE:
                OnImageComplete(event);
                break;
            default: return;
        }
    }

    void OnImageComplete(ArkUI_NodeEvent *event)
    {
        enum ComponentDataIndex {
            LOADING_STATUS_INDEX = 0,
            WIDTH_INDEX,
            HEIGHT_INDEX,
            COMPONENT_WIDTH_INDEX,
            COMPONENT_HEIGHT_INDEX,
            CONTENT_OFFSET_X_INDEX,
            CONTENT_OFFSET_Y_INDEX,
            CONTENT_WIDTH_INDEX,
            CONTENT_HEIGHT_INDEX
        };

        // 仅触发主图加载完毕时的OnComplete回调，且避免动图每一帧频繁触发
        if (!triggerOnCompleteCallback_) {
            return;
        }

        if (onImageComplete_ != nullptr) {
            auto componentEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event);
            if (componentEvent->data[LOADING_STATUS_INDEX].i32 == 1) {
                triggerOnCompleteCallback_ = false;
                ImageKnifeTrace trace("DrawingComplete", GetImageKnifeRequestInternal());
                trace.StartSyncTrace();
                // 在渲染完成时标记时间
                GetImageKnifeRequestInternal()->MarkDisplayEndTime();
            }

            onImageComplete_({.loadingStatus = componentEvent->data[LOADING_STATUS_INDEX].i32,
                              .width = componentEvent->data[WIDTH_INDEX].f32,
                              .height = componentEvent->data[HEIGHT_INDEX].f32,
                              .componentWidth = componentEvent->data[COMPONENT_WIDTH_INDEX].f32,
                              .componentHeight = componentEvent->data[COMPONENT_HEIGHT_INDEX].f32,
                              .contentOffsetX = componentEvent->data[CONTENT_OFFSET_X_INDEX].f32,
                              .contentOffsetY = componentEvent->data[CONTENT_OFFSET_Y_INDEX].f32,
                              .contentWidth = componentEvent->data[CONTENT_WIDTH_INDEX].f32,
                              .contentHeight = componentEvent->data[CONTENT_HEIGHT_INDEX].f32});
        }
    }

    void UpdateDerivedNodeEvent(std::shared_ptr<ImageKnifeOption> option) override
    {
        IMAGE_KNIFE_CHECK(option == nullptr, "Null ImageKnifeOption");
        if (option->onComplete == nullptr && onImageComplete_ != nullptr) {
            // 避免遗漏事件反注册
            GetNodeAPI()->unregisterNodeEvent(handle, NODE_IMAGE_ON_COMPLETE);
        } else if (option->onComplete != nullptr && onImageComplete_ == nullptr) {
            // 旧的option没启用OnComplete  新的启用了，需注册事件
            GetNodeAPI()->registerNodeEvent(handle, NODE_IMAGE_ON_COMPLETE, 0, nullptr);
        }
        // 更新OnComplete 回调状态
        onImageComplete_ = option->onComplete;
    }

    // 不能在析构里调该虚函数
    void RemoveDisplayedImage() override
    {
        GetNodeAPI()->resetAttribute(handle, NODE_IMAGE_SRC);
    }

    bool IsAnimator() const override
    {
        return false;
    }
};

}

#endif // IMAGE_KNIFE_C_KEKE_IMAGEKNIFE_NODE_IMAGE_H
